package cn.wandersnail.bluetooth;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.Arrays;

import cn.wandersnail.commons.util.StringUtils;

/**
 * date: 2020/5/5 20:53
 * author: zengfansheng
 */
class SocketConnection {
    private BluetoothSocket socket;
    private final BluetoothDevice device;
    private OutputStream outStream;
    private final ConnectionImpl connection;

    /**
     * UUID缓存
     */
    private final UUIDWrapper uuidWrapper;

    @SuppressLint("MissingPermission")
    SocketConnection(ConnectionImpl connection, BTManager btManager, BluetoothDevice device, UUIDWrapper uuidWrapper, ConnectCallback callback) {
        this.device = device;
        this.connection = connection;
        this.uuidWrapper = uuidWrapper;
        BluetoothSocket tmp;
        try {
            connection.changeState(Connection.STATE_CONNECTING, false);
            tmp = device.createRfcommSocketToServiceRecord(uuidWrapper.getUuid());
        } catch (IOException e) {
            try {
                Method method = device.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
                tmp = (BluetoothSocket) method.invoke(device, 1);
            } catch (Throwable t) {
                onConnectFail(connection, callback, "Connect failed: Socket's create() method failed", e);
                return;
            }
        }
        socket = tmp;
        btManager.getExecutorService().execute(() -> {
            InputStream inputStream;
            OutputStream tmpOut;
            try {
                btManager.stopDiscovery();//停止搜索
                socket.connect();
                inputStream = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
                if (!connection.isReleased()) {
                    onConnectFail(connection, callback, "Connect failed: " + e.getMessage(), e);
                }
                return;
            }
            connection.changeState(Connection.STATE_CONNECTED, true);
            if (callback != null) {
                callback.onSuccess();
            }
            connection.callback(MethodInfoGenerator.onConnectionStateChanged(device, uuidWrapper, Connection.STATE_CONNECTED));
            outStream = tmpOut;
            byte[] buffer = new byte[1024];
            int len;
            // 用于保存当前已读取到的数据
            ByteArrayOutputStream currentData = new ByteArrayOutputStream();
            while (true) {
                try {
                    len = inputStream.read(buffer);

                    // 如果读取到了EOF，则退出循环
                    if (len == -1) {
                        break;
                    }

                    for (int i = 0; i < len; i++) {
                        byte b = buffer[i];
                        // 将当前字节添加到当前数据流中
                        currentData.write(b);
                        // 当前字节为0xff时，发送之前累积的数据
                        if (b == (byte) 0xff) {
                            byte[] data = currentData.toByteArray();
                            Log.d("Receive data =>> ", StringUtils.toHex(data));
//                            Log.d("Receive Size =>> ", data.length+"");
                            if (data.length == 512){
                                connection.callback(MethodInfoGenerator.onRead(device, uuidWrapper, data));
                            }
                            currentData.reset(); // 清空当前数据
                        }
                    }
                } catch (IOException e) {
                    if (!connection.isReleased()) {
                        connection.changeState(Connection.STATE_DISCONNECTED, false);
                    }
                    break;
                }
            }
            close();
        });
    }

//    outStream = tmpOut;
//    byte[] buffer = new byte[2048];
//    int len;
//    byte[] tempBuffer = new byte[512]; // 用于临时存储数据
//    int tempBufferPos = 0; // 记录临时缓冲区中的当前位置
//
//            while (true) {
//        try {
//            len = inputStream.read(buffer);
//
//            for (int i = 0; i < len; i++) {
//                if (buffer[i] == (byte) 0xFF && tempBufferPos == 0) {
//                    // 找到0xFF, 从下一个位置开始处理
//                    i++;
//
//                    // 将剩余部分复制到临时缓冲区
//                    int remaining = len - i;
//                    System.arraycopy(buffer, i, tempBuffer, 0, Math.min(remaining, tempBuffer.length));
//                    tempBufferPos = Math.min(remaining, tempBuffer.length);
//
//                    // 如果临时缓冲区已满，则发送数据
//                    if (tempBufferPos == tempBuffer.length) {
//                        byte[] data = Arrays.copyOf(tempBuffer, tempBuffer.length);
//                        Log.d("Receive data =>> ", StringUtils.toHex(data));
//                        connection.callback(MethodInfoGenerator.onRead(device, uuidWrapper, data));
//                        tempBufferPos = 0;
//                    }
//                } else if (tempBufferPos > 0) {
//                    // 如果已经在收集数据
//                    if (tempBufferPos < tempBuffer.length) {
//                        tempBuffer[tempBufferPos++] = buffer[i];
//
//                        // 如果临时缓冲区已满，则发送数据
//                        if (tempBufferPos == tempBuffer.length) {
//                            byte[] data = Arrays.copyOf(tempBuffer, tempBuffer.length);
//                            Log.d("Receive data =>> ", StringUtils.toHex(data));
//                            connection.callback(MethodInfoGenerator.onRead(device, uuidWrapper, data));
//                            tempBufferPos = 0;
//                        }
//                    }
//                }
//            }
//        } catch (IOException e) {
//            if (!connection.isReleased()) {
//                connection.changeState(Connection.STATE_DISCONNECTED, false);
//            }
//            break;
//        }
//    }
//    close();

    private void onConnectFail(ConnectionImpl connection, ConnectCallback callback, String errMsg, IOException e) {
        connection.changeState(Connection.STATE_DISCONNECTED, true);
        if (BTManager.isDebugMode) {
            Log.w(BTManager.DEBUG_TAG, errMsg);
        }
        close();
        if (callback != null) {
            callback.onFail(errMsg, e);
        }
        connection.callback(MethodInfoGenerator.onConnectionStateChanged(device, uuidWrapper, Connection.STATE_DISCONNECTED));
    }

    void write(WriteData data) {
        if (outStream != null && !connection.isReleased()) {
            try {
                outStream.write(data.value);
                BTLogger.instance.d(BTManager.DEBUG_TAG, "Write success. tag = " + data.tag);
                if (data.callback == null) {
                    connection.callback(MethodInfoGenerator.onWrite(device, uuidWrapper, data.tag, data.value, true));
                } else {
                    data.callback.onWrite(device, data.tag, data.value, true);
                }
            } catch (IOException e) {
                onWriteFail("Write failed: " + e.getMessage(), data);
            }
        } else {
            onWriteFail("Write failed: OutputStream is null or connection is released", data);
        }
    }

    private void onWriteFail(String msg, WriteData data) {
        if (BTManager.isDebugMode) {
            Log.w(BTManager.DEBUG_TAG, msg);
        }
        if (data.callback == null) {
            connection.callback(MethodInfoGenerator.onWrite(device, uuidWrapper, data.tag, data.value, false));
        } else {
            data.callback.onWrite(device, data.tag, data.value, false);
        }
    }

    void close() {
        if (socket != null) {
            try {
                socket.close();
                socket = null;
            } catch (Throwable e) {
                BTLogger.instance.e(BTManager.DEBUG_TAG, "Could not close the client socket: " + e.getMessage());
            }
        }
    }

    boolean isConnected() {
        return socket != null && socket.isConnected();
    }

    static class WriteData {
        String tag;
        byte[] value;
        WriteCallback callback;

        WriteData(String tag, byte[] value) {
            this.tag = tag;
            this.value = value;
        }
    }
}
